<?php

require_once(_ABSPATH.'/lib/Netmask.php');

/**
* Transform list textarea to array
*
* The "list of machines" field on the nessquik forms
* gives me a string of possible machines that can
* be scanned. To process the machines correctly, I
* need to transform that string to an array of machines.
* Some people separate their machines by commas, others
* by newlines. This function handles creating that
* array of possible machines.
*
* @param string $list Textarea string containing the
*	list of potential machines that needs to be
*	checked by nessquik.
* @return array Textarea list transformed into an array
*	that nessquik can work with.
*/
function list_entries_to_array($list) {
	$list	= str_replace(' ','', $list);

	/**
	* I wanted commas, Zingelman wanted newlines, Nordwall
	* made me remember about \r\n. Now, they all become commas
	*
	* From ngkongs@gmail.com's comment to the nl2br function
	* on the PHP site...
	*
	*	windows = \r\n
	*	unix = \n
	*	mac = \r
	*/
	$list	= str_replace(array("\r\n","\r","\n"), ",", $list);
	$list	= trim($list);
	$data	= array();

	if (strpos($list, ',') !== false) {
		$data = explode(',', $list);
	} else {
		$data = array($list);
	}

	$data	= array_filter($data, 'strip_empty');
	$data	= array_unique($data);

	return $data;
}

/**
* Create the machine list
*
* The machine list is the "dirty" list of machines.
* All the machines that a user specified in the list
* input need to be checked against the list of
* machines that the user is allowed to scan. The
* machine list is the initial list that is created.
* Machines that have been verified are then moved
* to the ok_computers list. Only machines in the
* ok_computers list will be saved to the database
* for use by Nessus later on.
*
* @param array $data Array of list items as would be
*	generated by the list_entries_to_array function
* @return array Machine list that can be used later
*	in processing as a starting point for what
*	needs to be verified.
* @see list_entries_to_array
*/
function list_items_to_machine_list($data) {
	$_net 		= Netmask::getInstance();
	$machine_list	= array();

	foreach ($data as $key => $val) {
		$val 	= trim($val);
		$tmp	= array();
		$cidrs	= array();

		if (is_ip($val)) {
			$machine_list[] 	= $val;
		} else if (is_cidr($val)) {
			$machine_list[] 	= $val;
		} else if (is_range($val)) {
			$cidrs			= $_net->split_cidrs($val);
			$machine_list		= array_merge($machine_list, $cidrs);
		} else if (is_short_range($val)) {
			$cidrs			= $_net->split_cidrs($val);
			$machine_list		= array_merge($machine_list, $cidrs);
		} else if (is_vhost($val)) {
			$machine_list[] 	= $val;
		} else {
			$machine_list[] 	= strtoupper($val);
		}
	}

	// Filter out empty array elements if there are any
	$machine_list = array_filter($machine_list, "strip_empty");

	return $machine_list;
}

/**
* Skims the whitelist to match nodes
*
* Skimming involves just looping over the list of
* machines and seeing if there is a direct match in
* the whitelist. It will not however match an IP
* address in a CIDR block, that requires deeper
* digging.
*
* @param array $machine_list List of questionable
*	machines to check the whitelist for
* @param array $whitelist List of whitelisted machines
*	that the machine list items will be checked
*	against
* @param array $ok_computers List of computers that
*	the user is allowed to scan because the
*	machine is registered, or whitelisted, etc.
* @return array An updated machine list who has had
*	it's items that were in the whitelist stripped out
*/
function skim_whitelist_to_verify_nodes($machine_list, $whitelist, &$ok_computers) {
	$needs_checking	= false;

	foreach ($machine_list as $key => $comp) {
		$vhost = '';

		// vhosts are really the exception here because of their format
		if (is_vhost($comp)) {
			$vhost 	= $comp;
			$tmp 	= substr($comp,1,-1);
			$comp 	= gethostbyname($tmp);
		}

		if (in_array($comp, $whitelist)) {
			$needs_checking = false;
		} else if (in_array($comp,$ok_computers)) {
			$needs_checking = false;
		} else if (in_array(gethostbyname($comp), $whitelist)) {
			$needs_checking = false;
		} else {
			$needs_checking = true;
		}

		if (!$needs_checking) {
			// Maintain the vhost format for nessus
			if(is_vhost($vhost)) {
				$ok_computers[] = ":vho:".$tmp.'['.$comp.']';
			} else {
				$ok_computers[] = ":whi:$comp";
			}

			$machine_list[$key] = '';
		}
	}

	/**
	* Filter out empty elements from the array. The strip_empty function
	* is defined in lib/functions.php
	*/
	$machine_list = array_filter($machine_list, "strip_empty");

	return $machine_list;
}

/**
* Deeper scan of the whitelist to match entries
*
* A deeper whitelist scan is needed if the user
* has specified a range, CIDR block, vhost, etc,
* because these particular types could be stored
* in the whitelist in a number of ways. This
* method performs the deeper interrogation of the
* whitelist to try to definitively proove that
* a specified machine is or is not in the whitelist
*
* @param array $wl Whitelist to check for machines in
* @param array $machine_list List of questionable
*	machines that need to be checked for in the
*	whitelist
* @param array $ok_computers List of computers that
*	have been deemed "ok", aka the user is
*	allowed to scan them
*/
function whitelist_dig_deep_verify_nodes(&$wl, &$machine_list, &$ok_computers) {
	$_nm = Netmask::getInstance();

	foreach ($machine_list as $key3 => $val3) {
		foreach ($wl as $key4 => $val4) {
			// If the entry is a cidr and the whitelist is a cidr
			if ((is_cidr($val4)) && (is_cidr($val3))) {
				if ($_nm->match_cidr($val4,$val3)) {
					$ok_computers[] 	= ":whi:$val3";
					$machine_list[$key3]	= '';
				}
			// if the entry is an ip and the whitelist is a cidr	
			} else if ((is_cidr($val4)) && (is_ip($val3))) {
				if ($_nm->net_match($val4, $val3)) {
					$ok_computers[] 	= ":whi:$val3";
					$machine_list[$key3]	= '';
				}
			// if the entry is a vhost and the whitelist is a cidr
			} else if ((is_cidr($val4)) && (is_vhost($val3))) {
				$vhost 	= $val3;
				$tmp 	= substr($val3,1,-1);
				$comp 	= gethostbyname($tmp);

				if ($_nm->net_match($val4, $comp)) {
					$ok_computers[] 	= ":vho:$vhost";
					$machine_list[$key3]	= '';
				}
			// if entry is a ?hostname? and whitelist is a cidr
			} else if ((is_cidr($val4)) && ($val3 != '')) {
				$val3 = gethostbyname($val3);

				// Check if it's in the CIDR range and remove it
				// if it is, because that means it's whitelisted
				if ($_nm->net_match($val4, $val3)) {
					// Not keeping the hostname because whitelist
					// entries can only be IP based?
					$ok_computers[] 	= ":whi:$val3";
					$machine_list[$key3]	= '';
				}
			}
		}
	}
}

/**
* Check if either a registered host or IP is in the list
* of machines sent to the backend
*
* If the user has specified a machine that is registered
* to them, then that machine can be instantly moved to
* the list of machines that are allowed to be scanned.
* This function will compare both the IP and the hostname
* of the entered item to the list of registered machines
* to see if the user is allowed to scan it.
*
* @param array $accepted_list List of registered machines
*	to compare the entered list of targets with
* @param array $ok_computers List of targets that the user
*	is allowed to scan
* @param array $machine_list List of targets that I'm not
*	sure the user is allowed to scan. This list will
*	be checked with the entries in the $accepted_list
*	to see if the user is allowed to scan the machines
*/
function check_registered_host_or_ip_in_list($accepted_list, &$ok_computers, &$machine_list) {
	$ips 		= array_keys($accepted_list);
	$hosts 		= array_values($accepted_list);

	/**
	* Need to go through list of machines sent and find out the
	* ones that the user is not allowed to scan.
	*
	* The accepted list returns a list of hostnames indexed by IP
	* address. The code above that populates the machine_list variable
	* doesnt index by IP address.
	*
	* I separated the two lists (IP and hostname) into separate arrays
	* and in the IF statements below, I check both arrays to make sure
	* I havent missed the item I'm searching for
	*/
	foreach ($machine_list as $key => $comp) {
		if (in_array($comp, $hosts)) {
			/**
			* I'm prefixing the item with the registered
			* computer delimiter because the logic below
			* can only determine items as if they would
			* be registered machines.
			*
			* For example, MISCOMP doesnt let you own netblocks.
			* The below code may need to be modified to
			* support clusters
			*/
			$ok_computers[] 	= ":reg:$comp";
			$machine_list[$key] 	= '';
		} else if (in_array($comp, $ips)) {
			$ok_computers[] 	= ":reg:$comp";
			$machine_list[$key]	= '';
		}
	}
}

/**
* Echo code to hide the spinner image
*
* On several javascript capable pages, a spinner is
* used to give the impression that the app is doing
* something. This function is used to hide the spinner
* image by emitting some javascript to the browser that
* will empty the contents of the div that holds the
* spinner
*
* @return boolean Always returns true
*/
function hide_spinner() {
	echo "<script type='text/javascript'>"
	. "try {\n"
	. "document.getElementById('work').innerHTML = '';\n"
	. "} catch(e) {}\n"
	. "</script>";

	return true;
}

?>
